﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;

namespace AutoCADDotNetLibrary
{
    /// <summary>
    /// 数据库的扩展
    /// </summary>
    public static class DatabaseExtention
    {
        /// <summary>
        /// 判断文件是否被程序占用
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static bool IsFileInUse(string fileName)
        {
            bool inUse = true;
            if (File.Exists(fileName))
            {
                try
                {
                    using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.None))
                    {
                        inUse = false;
                    }
                }
                catch (Exception)
                {

                }
                return inUse;//true表示正在使用,false没有使用
            }
            else
            {
                return false;//文件不存在则一定没有被使用
            }
        }

        /// <summary>
        /// 实体输出到新创建的dwg文件
        /// </summary>
        /// <param name="db">dwg数据库</param>
        /// <param name="ents">实体集合</param>
        /// <param name="saveFileName">保存文件位置</param>
        /// <param name="version">版本（默认为DwgVersion.Current）</param>
        public static void OutputNewDWGFile(this Database db, IEnumerable<Entity> ents, string saveFileName, DwgVersion? version = null)
        {
            ObjectIdCollection ids = new ObjectIdCollection(ents.Select(x => x.ObjectId).ToArray());
            using (Database copyDb = new Database(true, true))
            {
                //实体导入到copyToFile数据库
                using (Transaction trans = copyDb.TransactionManager.StartTransaction())
                {
                    BlockTable bt = (BlockTable)trans.GetObject(copyDb.BlockTableId, OpenMode.ForRead);
                    BlockTableRecord btr = (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead);
                    db.WblockCloneObjects(ids, btr.ObjectId, new IdMapping(), DuplicateRecordCloning.Replace, false);
                    trans.Commit();
                }
                if (version == null)
                {
                    version = db.OriginalFileSavedByVersion;
                }
                copyDb.SaveAs(saveFileName, version.Value);
            }
            //删除产生的.bak文件
            if (File.Exists(Path.GetDirectoryName(saveFileName) + "\\" + Path.GetFileNameWithoutExtension(saveFileName) + ".bak"))
            {
                File.Delete(Path.GetDirectoryName(saveFileName) + "\\" + Path.GetFileNameWithoutExtension(saveFileName) + ".bak");
            }
        }

        /// <summary>
        /// 实体复制到DWGFile
        /// </summary>
        /// <param name="db">dwg数据库</param>
        /// <param name="copyToFile">复制的文件</param>
        /// <param name="ents">实体集合</param>
        /// <param name="saveFileName">保存位置</param>
        /// <param name="version">版本（默认为DwgVersion.Current）</param>
        public static void CopyToDWGFile(this Database db, string copyToFile, IEnumerable<Entity> ents, string saveFileName, DwgVersion? version = null)
        {
            ObjectIdCollection ids = new ObjectIdCollection(ents.Select(x => x.ObjectId).ToArray());
            using (Database copyDb = new Database(false, true))
            {
                copyDb.ReadDwgFile(copyToFile, System.IO.FileShare.Read, true, null);
                //实体导入到copyToFile数据库
                using (Transaction trans = copyDb.TransactionManager.StartTransaction())
                {
                    BlockTable bt = (BlockTable)trans.GetObject(copyDb.BlockTableId, OpenMode.ForRead);
                    BlockTableRecord btr = (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead);
                    db.WblockCloneObjects(ids, btr.ObjectId, new IdMapping(), DuplicateRecordCloning.Replace, false);
                    trans.Commit();
                }
                if (version == null)
                {
                    version = db.OriginalFileSavedByVersion;
                }
                copyDb.SaveAs(saveFileName, version.Value);
            }
            //删除产生的.bak文件
            if (File.Exists(Path.GetDirectoryName(copyToFile) + "\\" + Path.GetFileNameWithoutExtension(copyToFile) + ".bak"))
            {
                File.Delete(Path.GetDirectoryName(copyToFile) + "\\" + Path.GetFileNameWithoutExtension(copyToFile) + ".bak");
            }
        }

        /// <summary>
        /// 操作数据库(问题Dbtext,居中不行)
        /// </summary>
        /// <param name="dwgFile">dwg文件</param>
        /// <param name="act">操作数据库(先于实体)</param>
        /// <param name="oper">操作实体方法(已有的实体)</param>
        /// <param name="isSave">是否保存</param>
        /// <param name="saveFileName">保存位置</param>
        /// <param name="version">版本（默认为DwgVersion.Current）</param>
        public static void OperateDWGFile(string dwgFile, Action<Database> act, Action<Entity[]> oper, bool isSave = false, string saveFileName = null, DwgVersion? version = null)
        {
            using (Database db = new Database(false, true))
            {
                db.ReadDwgFile(dwgFile, System.IO.FileShare.Read, true, null);
                using (Transaction trans = db.TransactionManager.StartTransaction())
                {
                    BlockTable bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead);
                    BlockTableRecord btr = (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead);

                    //操作其他表
                    act?.Invoke(db);

                    //操作实体
                    oper?.Invoke(btr.Cast<ObjectId>().Select(x => trans.GetObject(x, OpenMode.ForWrite, false, true)).Cast<Entity>().ToArray());
                    trans.Commit();
                }
                if (isSave)
                {
                    if (version == null)
                    {
                        version = db.OriginalFileSavedByVersion;
                    }
                    db.SaveAs(saveFileName, version.Value);
                }
            }
            if (File.Exists(Path.GetDirectoryName(dwgFile) + "\\" + Path.GetFileNameWithoutExtension(dwgFile) + ".bak"))
            {
                File.Delete(Path.GetDirectoryName(dwgFile) + "\\" + Path.GetFileNameWithoutExtension(dwgFile) + ".bak");
            }
        }

        /// <summary>
        /// 导入dwg文件到块定义
        /// </summary>
        /// <param name="db">dwg数据库</param>
        /// <param name="importFile">导入文件</param>
        /// <param name="blockName">块名</param>
        /// <returns>块定义ID</returns>
        public static ObjectId ImportToBlockFromDwg(this Database db, string importFile, string blockName)
        {
            using (Database importDb = new Database(false, true))
            {
                importDb.ReadDwgFile(importFile, FileOpenMode.OpenForReadAndAllShare, true, null);
                return db.Insert(blockName, importDb, true);
            }
        }

        /// <summary>
        /// 导入dwg文件到实体集合中（实体没有加入到空间中）
        /// </summary>
        /// <param name="db">数据库</param>
        /// <param name="importFile">导入文件</param>
        /// <param name="position">位置</param>
        /// <returns>实体集合</returns>
        public static IEnumerable<Entity> ImportToEntitySetFromDwg(this Database db, string importFile, Point3d position)
        {
            //得到临时的块定义名name
            Transaction trans = db.TransactionManager.TopTransaction;
            BlockTable bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForWrite);
            string name = "temp";
            int index = 0;
            while (bt.Has(name))
            {
                name = "temp" + index++;
            }

            //通过块参照分解得到实体
            ObjectId blockid = db.ImportToBlockFromDwg(importFile, name);
            DBObjectCollection entitySet;
            using (BlockReference blref = new BlockReference(position, blockid))
            {
                entitySet = new DBObjectCollection();
                blref.Explode(entitySet);
            }

            //删除临时块名称
            BlockTableRecord btr = (BlockTableRecord)trans.GetObject(blockid, OpenMode.ForWrite);
            if (btr.IsCanDelete())
            {
                btr.Erase();
            }

            return entitySet.Cast<Entity>();
        }

        /// <summary>
        /// 加载lsp文件
        /// </summary>
        /// <param name="doc">文档</param>
        /// <param name="lspFile">lsp文件位置</param>
        public static void LoadLsp(this Document doc, string lspFile)
        {
            doc.SendStringToExecute("(LOAD \"" + lspFile.Replace("\\", "/") + "\") ", true, false, false);
        }

        /// <summary>
        /// 加载dll文件
        /// </summary>
        /// <param name="doc">文档</param>
        /// <param name="dllFile">dll文件位置</param>
        public static void LoadDLL(this Document doc, string dllFile)
        {
            doc.SendStringToExecute("(command \"netload\" \"" + dllFile.Replace("\\", "/") + "\") ", true, false, false);
        }
    }
}